#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define LEFT "["
#define RIGHT "]"
#define LABLE "$"
#define DELIM " \t"

int lastcode = 0;
int quit = 0;
char commandline[LINE_SIZE];
char* argv[ARGC_SIZE];
char pwd[LINE_SIZE];
char hostname[LINE_SIZE];

// 环境变量
char myenv[LINE_SIZE];

char* GetHostName()
{
    //return getenv("HOSTNAME");
    gethostname(hostname, sizeof(hostname));
    return hostname;
}

char* GetUserName()
{
    return getenv("USER");
}

void GetPwd()
{
    getcwd(pwd, sizeof(pwd));
}

void SplitPwd()
{
    int j = 0;
    int len = strlen(pwd);
    for (int i = len - 1; i >= 0; i--)
    {
        if (pwd[i] == '/')
        {
            j = i;
            break;
        }
    }
    if (!j) {
        pwd[0] = '/';
        pwd[1] = '\0';
        return;
    }
    int l = 0;
    for (int i = j + 1; i < len; i++)
    {
        pwd[l++] = pwd[i];
    }
    pwd[l] = 0;
}

void Interact(char* cline, size_t size)
{
    GetPwd();
    SplitPwd();
    
    printf(LEFT"%s@%s %s"RIGHT""LABLE" ", GetUserName(), GetHostName(), pwd);
    char* s = fgets(cline, size, stdin);
    assert(s);
    (void)s;
    cline[strlen(cline)-1] = '\0';
}

int SplitString(char* _argv[], char* cline)
{
    int i = 0;
    _argv[i++]  = strtok(cline, DELIM);
    while (_argv[i++] = strtok(NULL, DELIM));
    return i - 1;
}

void NormalExcute(char* argv[])
{
    pid_t id = fork();  
    if (id < 0)
    {
        perror("fork");
        return;
    }
    else if (id == 0)
    {
        execvp(argv[0], argv);
        exit(0);
    }
    else
    {
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if (ret == id)
        {
            lastcode = WEXITSTATUS(status);
        }
    }
}

int BuildExcute(int _argc, char* _argv[])
{   
    if (_argc == 2 && strcmp(_argv[0], "cd") == 0)
    {
        chdir(_argv[1]);
        GetPwd();
        sprintf(getenv("PWD"), "%s", pwd);
        return 1;
    }
    else if(_argc == 2 && strcmp(_argv[0], "export") == 0)
    {
        strcpy(myenv, _argv[1]);
        putenv(myenv);
        return 1;
    } 
    else if (_argc == 2 && strcmp(_argv[0], "echo") == 0)
    {
        if (strcmp(_argv[1], "$?") == 0)
        {
            printf("%d\n", lastcode);
            lastcode = 0;
        }
        if (*_argv[1] == '$')
        {
            char* val = getenv(_argv[1] + 1);
            if (val) printf("%s\n", val);
        }
        else
        {
            printf("%s\n", _argv[1]);
        }
        return 1;
    }
    
    // 单独处理ls
    if (strcmp(_argv[0], "ls") == 0)
    {
        _argv[_argc++] = "--color";
        _argv[_argc] = NULL;
    }
    return 0;
}

int main()
{
    while (!quit)
    {
        Interact(commandline, sizeof(commandline)); 
        int argc = SplitString(argv, commandline);
        if (argc == 0) continue;
        
        int n = BuildExcute(argc, argv);
     
        if (!n)
            NormalExcute(argv);     
    }
    return 0;
}
